/*
 * mano.c
 *
 *  Created on: 04/04/2012
 *      Author: Jorge Antonio García Galicia
 */


#include <GL/glut.h>
#include <GL/glu.h>
#include <stdlib.h>
#include <time.h>

#define MUNDO 6.0f
//Variables globales que guardan el tope de las coordenadas de mundo
float xRot, yRot, zRot, scale;
int solid;
int play;
int projection;
float aspect;
int deltas[5][2];
float angulos[5][2];

void inicializar (void);
void redimensiona (int alto, int ancho);
void dibuja (void);
void teclado (unsigned char key, int cx, int cy);
void tecladoEspecial (int key, int cy, int cx);
void dibujaEscena (void);
void dibujaFalange(void);
void dibujaDedo(float, float);
void dibujaPulgar(float);
void dibujaMano(void);
void setProjection(float);
void resetAngles(void);
void animacion(void);
void setAngles(void);

int main(int argc, char** argv) {

   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (640, 480);
   glutInitWindowPosition (100, 105);
   glutCreateWindow ("Mano de Robot");
   inicializar();

   glutDisplayFunc(dibuja);
   glutReshapeFunc(redimensiona);
   glutKeyboardFunc(teclado);
   glutSpecialFunc(tecladoEspecial);
   glutIdleFunc(animacion);

   glutMainLoop();

   return 0;
}

void inicializar () {

   glClearColor(0.0, 0.0, 0.0, 1.0);
   glEnable(GL_DEPTH_TEST);
   solid = 1;
   xRot = yRot = zRot = 0.0;
   scale = 1.0;
   play = 0;
   projection = 0;
   srand(time(NULL));
   resetAngles();

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);

}

void redimensiona (int ancho, int alto) {
   glViewport (0, 0, ancho, alto);

   if (alto == 0){
   	  alto = 1;
   }

   aspect = (float) ancho / (float) alto;
}

void teclado (unsigned char key, int cx, int cy) {

	switch (key) {
		case 27:
		   exit(0);
		break;

		case '+':
			scale += 0.1;
		break;

		case '-':
			scale -= 0.1;
		break;

		case 'o':
			solid = !(solid);
		break;

		case 'a':
			play = !(play);
			if (!play) {
				resetAngles();
			} else {
				setAngles();
			}
		break;

		case 'p':
			projection = !(projection);
		break;

		default: break;
	}

	glutPostRedisplay();
}

void tecladoEspecial (int key, int cy, int cx) {

	switch (key) {
		case GLUT_KEY_UP:
			xRot += 5.0;
		break;

		case GLUT_KEY_DOWN:
			xRot -= 5.0;
		break;

		case GLUT_KEY_LEFT:
			yRot -= 5.0;
		break;

		case GLUT_KEY_RIGHT:
			yRot += 5.0;
		break;

		case GLUT_KEY_PAGE_UP:
			zRot += 5.0;
		break;

		case GLUT_KEY_PAGE_DOWN:
			zRot -= 5.0;
		break;

		default: break;
	}

	glutPostRedisplay();
}

void dibuja (void) {

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	setProjection(aspect);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glPushMatrix();
		if (!projection) {
			glTranslatef(0.0, 0.0, -2.0 * MUNDO);
		}
		glRotatef(xRot, 1.0, 0.0, 0.0);
		glRotatef(yRot, 0.0, 1.0, 0.0);
		glRotatef(zRot, 0.0, 0.0, 1.0);
		glScalef(scale, scale, scale);
		dibujaEscena();
	glPopMatrix();

	glutSwapBuffers();
}

void dibujaEscena () {
	glPushMatrix();
		dibujaMano();
	glPopMatrix();
}

void dibujaFalange(void) {
	glColor3f(1.0, 0.0, 0.0);
	solid ? glutSolidSphere(0.25, 10.0, 10.0) : glutWireSphere(0.25, 10.0, 10.0);
	glPushMatrix();
		glTranslatef(0.0, 0.0, -1.0);
		glPushMatrix();
			glScalef(0.5, 0.5, 1.5);
			glColor3f(1.0, 1.0, 0.0);
			solid ? glutSolidCube(1.0) : glutWireCube(1.0);
		glPopMatrix();
	glPopMatrix();
}

void dibujaDedo(float angle1, float angle2) {
	dibujaFalange();
	glPushMatrix();
		glTranslatef(0.0, 0.0, -1.95);
		glRotatef(angle1, 1.0, 0.0, 0.0);
		glScalef(0.75, 0.75, 0.75);
		dibujaFalange();
		glPushMatrix();
			glTranslatef(0.0, 0.0, -1.89);
			glRotatef(angle2, 1.0, 0.0, 0.0);
			glScalef(0.65, 0.65, 0.65);
			dibujaFalange();
		glPopMatrix();
	glPopMatrix();
}

void dibujaPulgar(float angle) {
	dibujaFalange();
	glPushMatrix();
		glTranslatef(0.0, 0.0, -1.95);
		glRotatef(angle, 1.0, 0.0, 0.0);
		glScalef(0.75, 0.75, 0.75);
		dibujaFalange();
	glPopMatrix();
}

void dibujaMano(void) {
	glPushMatrix();
		//Muñeca
		glPushMatrix();
			glTranslatef(0.0, -0.375, 0.0);
			glScalef(2.0, 0.75, 0.75);
			glColor3f(1.0, 0.0, 0.0);
			solid ? glutSolidCube(1.0) : glutWireCube(1.0);
		glPopMatrix();
		//Palma
		glPushMatrix();
			glTranslatef(0.0, 0.25, -1.3);
			glScalef(3.0, 0.5, 3.0);
			glColor3f(1.0, 1.0, 0.0);
			solid ? glutSolidCube(1.0) : glutWireCube(1.0);
		glPopMatrix();
		//Dedo 1
		glPushMatrix();
			glTranslatef(1.25, 0.25, -3.0);
			glRotatef(angulos[0][0], 1.0, 0.0, 0.0);
			glScalef(1.0, 0.65, 1.0);
			dibujaDedo(angulos[0][1], 10.0);
		glPopMatrix();
		//Dedo 2
		glPushMatrix();
			glTranslatef(0.45, 0.25, -3.0);
			glRotatef(angulos[1][0], 1.0, 0.0, 0.0);
			glScalef(1.0, 1.0, 1.0);
			dibujaDedo(angulos[1][1], 10.0);
		glPopMatrix();
		//Dedo 3
		glPushMatrix();
			glTranslatef(-0.45, 0.25, -3.0);
			glRotatef(angulos[2][0], 1.0, 0.0, 0.0);
			glScalef(1.0, 0.85, 1.0);
			dibujaDedo(angulos[2][1], 10.0);
		glPopMatrix();
		//Dedo 4
		glPushMatrix();
			glTranslatef(-1.25, 0.25, -3.0);
			glRotatef(angulos[3][0], 1.0, 0.0, 0.0);
			glScalef(1.0, 0.55, 1.0);
			dibujaDedo(angulos[3][1], 10.0);
		glPopMatrix();
		//Pulgar
		glPushMatrix();
			glTranslatef(-1.5, 0.25, -1.5);
			glRotatef(angulos[4][0], 0.0, 1.0, 0.0);
			glScalef(1.25, 1.25, 0.8);
			dibujaPulgar(angulos[4][1]);
		glPopMatrix();
	glPopMatrix();
}

void setProjection (float aspect) {
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	if (projection) {
		if (aspect <= 1.0) {
			glOrtho(-MUNDO, MUNDO, -MUNDO/aspect, MUNDO/aspect, -(MUNDO + 2.0), MUNDO + 2.0);
		} else {
			glOrtho(-MUNDO * aspect, MUNDO * aspect, -MUNDO, MUNDO, -(MUNDO + 2.0), MUNDO + 2.0);
		}
	} else {
		gluPerspective(40.0, aspect, MUNDO, 3.0 * MUNDO);
	}
}

void resetAngles() {
	int i;
	for (i = 0; i < 5; i++) {
		angulos[i][0] = 30.0;
		angulos[i][1] = 30.0;
		deltas[i][0] = 1;
		deltas[i][1] = 1;
	}
}

void animacion () {
	int i;

	if (play) {
		for (i = 0; i < 5; i++) {

			if (angulos[i][0] <= -10.0) {
				angulos[i][0] = -10.0;
				deltas[i][0] *= -1;
			} else if (angulos[i][0] >= 100.0) {
				angulos[i][0] = 100.0;
				deltas[i][0] *= -1;
			}

			angulos[i][0] += deltas[i][0];

			if (angulos[i][1] <= 0.0) {
				angulos[i][1] = 0.0;
				deltas[i][1] *= -1;
			} else if (angulos[i][1] >= 90.0) {
				angulos[i][1] = 90.0;
				deltas[i][1] *= -1;
			}

			angulos[i][1] += deltas[i][1];
		}
	}
	glutPostRedisplay();
}

void setAngles() {
	int i;

	for (i = 0; i < 5; i++) {
		angulos[i][0] = rand() % 110 - 10;
		angulos[i][1] = rand() % 90;
	}
}


